package com.my.lucky.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.my.lucky.entity.StockHotRank;
import com.my.lucky.repository.StockHotRankRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 榜单列表缓存工具类
 * 缓存日期（yyyy-MM-dd）的榜单列表，缓存2天
 */
@Component
public class RankListCacheUtil {

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * 缓存过期时间（2天，单位：毫秒）
     */
    private static final long CACHE_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000L;
    /**
     * 缓存存储
     */
    private final ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
    /**
     * 定时清理任务
     */
    private final ScheduledExecutorService cleanupExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
        Thread thread = new Thread(r, "RankListCache-Cleanup");
        thread.setDaemon(true);
        return thread;
    });
    @Autowired
    StockHotRankRepository stockHotRankRepository;

    public RankListCacheUtil() {
        // 每小时执行一次清理任务
        cleanupExecutor.scheduleAtFixedRate(this::cleanExpiredEntries, 1, 1, TimeUnit.HOURS);
    }

    /**
     * 根据日期字符串获取缓存的榜单列表
     *
     * @param dateStr 日期字符串（yyyy-MM-dd格式）
     * @return 榜单列表，如果缓存不存在或已过期则返回null
     */
    public List<StockHotRank> getRankList(String dateStr) {
        CacheEntry entry = cache.get(dateStr);
        if (entry != null && !entry.isExpired()) {
            return entry.getData();
        }

        // 如果缓存过期，移除该条目
        if (entry != null && entry.isExpired()) {
            cache.remove(dateStr);
        }


        return null;
    }

    /**
     * 昨天
     *
     * @return
     */
    public List<StockHotRank> getRankListYest() {
        DateTime yesterday = DateUtil.yesterday();
        String dateStr = yesterday.toLocalDateTime().format(DATE_FORMATTER);
        List<StockHotRank> rankList = getRankList(dateStr);
        if (CollUtil.isEmpty(rankList)) {
            Optional<LocalDateTime> maxCreateTimeBetween = stockHotRankRepository.findMaxCreateTimeBetween(DateUtil.beginOfDay(yesterday).toLocalDateTime(), DateUtil.endOfDay(yesterday).toLocalDateTime());
            if (maxCreateTimeBetween.isPresent()) {
                List<StockHotRank> byRankDate = stockHotRankRepository.findByRankDate(maxCreateTimeBetween.get());
                putRankList(dateStr, byRankDate);
                return byRankDate;
            }
        } else {
            return rankList;
        }
        return new ArrayList<>();
    }

    /**
     * 前天
     *
     * @return
     */
    public List<StockHotRank> getRankListBefor() {
        DateTime befor = DateUtil.offsetDay(new Date(), -2);
        String dateStr = befor.toLocalDateTime().format(DATE_FORMATTER);
        List<StockHotRank> rankList = getRankList(dateStr);
        if (CollUtil.isEmpty(rankList)) {
            Optional<LocalDateTime> maxCreateTimeBetween = stockHotRankRepository.findMaxCreateTimeBetween(DateUtil.beginOfDay(befor).toLocalDateTime(), DateUtil.endOfDay(befor).toLocalDateTime());
            if (maxCreateTimeBetween.isPresent()) {
                List<StockHotRank> byRankDate = stockHotRankRepository.findByRankDate(maxCreateTimeBetween.get());
                putRankList(dateStr, byRankDate);
                return byRankDate;
            }
        } else {
            return rankList;
        }
        return new ArrayList<>();
    }

    /**
     * 今天
     *
     * @return
     */
    public List<StockHotRank> getRankListToday() {
        Optional<LocalDateTime> maxCreateTimeBetween = stockHotRankRepository.findMaxCreateTimeBetween(DateUtil.beginOfDay(DateUtil.date()).toLocalDateTime(), DateUtil.endOfDay(DateUtil.date()).toLocalDateTime());
        if (maxCreateTimeBetween.isPresent()) {
            List<StockHotRank> byRankDate = stockHotRankRepository.findByRankDate(maxCreateTimeBetween.get());
            return byRankDate;
        }
        return new ArrayList<>();
    }

    /**
     * 根据LocalDate获取缓存的榜单列表
     *
     * @param date 日期
     * @return 榜单列表，如果缓存不存在或已过期则返回null
     */
    public List<StockHotRank> getRankList(LocalDate date) {
        String dateStr = date.format(DATE_FORMATTER);
        return getRankList(dateStr);
    }

    /**
     * 根据LocalDateTime获取缓存的榜单列表
     *
     * @param dateTime 日期时间
     * @return 榜单列表，如果缓存不存在或已过期则返回null
     */
    public List<StockHotRank> getRankList(LocalDateTime dateTime) {
        return getRankList(dateTime.toLocalDate());
    }

    /**
     * 缓存榜单列表
     *
     * @param dateStr  日期字符串（yyyy-MM-dd格式）
     * @param rankList 榜单列表
     */
    public void putRankList(String dateStr, List<StockHotRank> rankList) {
        if (dateStr != null && rankList != null) {
            cache.put(dateStr, new CacheEntry(rankList));
        }
    }

    /**
     * 缓存榜单列表
     *
     * @param date     日期
     * @param rankList 榜单列表
     */
    public void putRankList(LocalDate date, List<StockHotRank> rankList) {
        String dateStr = date.format(DATE_FORMATTER);
        putRankList(dateStr, rankList);
    }

    /**
     * 缓存榜单列表
     *
     * @param dateTime 日期时间
     * @param rankList 榜单列表
     */
    public void putRankList(LocalDateTime dateTime, List<StockHotRank> rankList) {
        putRankList(dateTime.toLocalDate(), rankList);
    }

    /**
     * 移除指定日期的缓存
     *
     * @param dateStr 日期字符串（yyyy-MM-dd格式）
     */
    public void removeRankList(String dateStr) {
        cache.remove(dateStr);
    }

    /**
     * 移除指定日期的缓存
     *
     * @param date 日期
     */
    public void removeRankList(LocalDate date) {
        String dateStr = date.format(DATE_FORMATTER);
        removeRankList(dateStr);
    }

    /**
     * 检查指定日期是否有缓存
     *
     * @param dateStr 日期字符串（yyyy-MM-dd格式）
     * @return 是否有有效缓存
     */
    public boolean hasCache(String dateStr) {
        CacheEntry entry = cache.get(dateStr);
        return entry != null && !entry.isExpired();
    }

    /**
     * 检查指定日期是否有缓存
     *
     * @param date 日期
     * @return 是否有有效缓存
     */
    public boolean hasCache(LocalDate date) {
        String dateStr = date.format(DATE_FORMATTER);
        return hasCache(dateStr);
    }

    /**
     * 获取缓存大小
     *
     * @return 缓存条目数量
     */
    public int getCacheSize() {
        return cache.size();
    }

    /**
     * 清空所有缓存
     */
    public void clearAll() {
        cache.clear();
    }

    /**
     * 清理过期的缓存条目
     */
    private void cleanExpiredEntries() {
        cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
    }

    /**
     * 获取缓存统计信息
     *
     * @return 缓存统计信息字符串
     */
    public String getCacheStats() {
        int totalEntries = cache.size();
        long expiredEntries = cache.values().stream()
                .mapToLong(entry -> entry.isExpired() ? 1 : 0)
                .sum();

        return String.format("缓存统计 - 总条目: %d, 过期条目: %d, 有效条目: %d",
                totalEntries, expiredEntries, totalEntries - expiredEntries);
    }

    /**
     * 销毁资源
     */
    public void destroy() {
        cleanupExecutor.shutdown();
        try {
            if (!cleanupExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                cleanupExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            cleanupExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
        clearAll();
    }

    /**
     * 缓存数据结构
     */
    private static class CacheEntry {
        private final List<StockHotRank> data;
        private final long createTime;

        public CacheEntry(List<StockHotRank> data) {
            this.data = data;
            this.createTime = System.currentTimeMillis();
        }

        public List<StockHotRank> getData() {
            return data;
        }

        public boolean isExpired() {
            return System.currentTimeMillis() - createTime > CACHE_EXPIRE_TIME;
        }

        public long getCreateTime() {
            return createTime;
        }
    }
} 